/*
 * \brief  Region manager session interface
 * \author Norman Feske
 * \date   2006-05-15
 */

/*
 * Copyright (C) 2006-2009 Norman Feske
 * Genode Labs, Feske & Helmuth Systementwicklung GbR
 *
 * This file is part of the Genode OS framework, which is distributed
 * under the terms of the GNU General Public License version 2.
 */

#ifndef _INCLUDE__RM_SESSION__RM_SESSION_H_
#define _INCLUDE__RM_SESSION__RM_SESSION_H_

#include <base/exception.h>
#include <base/stdint.h>
#include <base/signal.h>
#include <dataspace/capability.h>
#include <thread/capability.h>

namespace Genode {

	class Rm_session
	{
		protected:

			enum Opcode { ATTACH, DETACH, ADD_CLIENT, FAULT_HANDLER, STATE, DATASPACE };

		public:

			enum Fault_type {
				READY = 0, READ_FAULT = 1, WRITE_FAULT = 2, EXEC_FAULT = 3
			};

			/**
			 * State of region-manager session
			 *
			 * If a client accesses a location outside the regions attached to
			 * the region-manager session, a fault occurs and gets signalled to
			 * the registered fault handler. The fault handler, in turn needs
			 * the information about the fault address and fault type to
			 * resolve the fault. This information is represented by this
			 * structure.
			 */
			struct State
			{
				/**
				 * Type of occurred fault
				 */
				Fault_type type;

				/**
				 * Fault address
				 */
				addr_t addr;

				/**
				 * Default constructor
				 */
				State() : type(READY), addr(0) { }

				/**
				 * Constructor
				 */
				State(Fault_type fault_type, addr_t fault_addr) :
					type(fault_type), addr(fault_addr) { }
			};

			static const char *service_name() { return "RM"; }


			/*********************
			 ** Exception types **
			 *********************/

			class Attach_failed     : public Exception         { };
			class Invalid_dataspace : public Attach_failed     { };
			class Region_conflict   : public Attach_failed     { };

			class Invalid_thread    : public Exception { };
			class Out_of_memory     : public Exception { };


			/**
			 * Destructor
			 */
			virtual ~Rm_session() { }

			/**
			 * Map dataspace into local address space
			 *
			 * \param ds              capability of dataspace to map
			 * \param size            size of the locally mapped region
			 *                        default (0) is the whole dataspace
			 * \param offset          start at offset in dataspace
			 * \param use_local_addr  if set to true, attach the dataspace at
			 *                        the specified 'local_addr'
			 * \param local_addr      local destination address
			 *
			 * \throw Attach_failed   if dataspace is invalid
			 *                        or on region conflict
			 *
			 * \return                local address of mapped dataspace
			 *
			 */
			virtual void *attach(Dataspace_capability ds,
			                     size_t size = 0, off_t offset = 0,
			                     bool use_local_addr = false,
			                     addr_t local_addr = 0) = 0;

			/**
			 * Shortcut for attaching a dataspace at a predefined local address
			 */
			void *attach_at(Dataspace_capability ds, addr_t local_addr,
			                size_t size = 0, off_t offset = 0) {
				return attach(ds, size, offset, true, local_addr); }

			/**
			 * Remove region from local address space
			 */
			virtual void detach(void *local_addr) = 0;

			/**
			 * Add client to pager
			 *
			 * \param thread  thread that will be paged
			 * \throw         Invalid_thread
			 * \throw         Out_of_memory
			 * \return        capability to be used for page faults
			 *
			 * This method must be called at least once to establish a valid
			 * communication channel between the pager part of the region manager
			 * and the client thread.
			 */
			virtual Thread_capability add_client(Thread_capability thread) = 0;

			/**
			 * Register signal receiver for region-manager faults
			 */
			virtual void fault_handler(Signal_receiver_capability handler) = 0;

			/**
			 * Request current state of RM session
			 */
			virtual State state() = 0;

			/**
			 * Return dataspace representation of region-manager session
			 */
			virtual Dataspace_capability dataspace() = 0;
	};
}

#endif /* _INCLUDE__RM_SESSION__RM_SESSION_H_ */
